home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / prolog / sbprolog / amiga / modlibsr.zoo / $setof.P < prev    next >
Text File  |  1988-09-15  |  20KB  |  563 lines

  1. %   File   : SETOF.PL
  2. %   Author : R.A.O'Keefe
  3. %   Updated: 17 November 1983
  4. %   Purpose: define set_of/3, bag_of/3, findall/3, and findall/4
  5. %   Needs  : Not.Pl
  6. %
  7. %   Modified for SB-Prolog by Saumya K. Debray, May 1988.
  8. %   Some of the code for the SB-Prolog version, specifically
  9. %   the version of $findall/3 using buff_code, was written by
  10. %   David S. Warren (in 1986?).
  11.  
  12. /*  This file defines two predicates which act like setof/3 and bagof/3.
  13.     I have seen the code for these routines in Dec-10 and in C-Prolog,
  14.     but I no longer recall it, and this code was independently derived
  15.     in 1982 by me and me alone.
  16.  
  17.     Most of the complication comes from trying to cope with free variables
  18.     in the Filter; these definitions actually enumerate all the solutions,
  19.     then group together those with the same bindings for the free variables.
  20.     There must be a better way of doing this.  I do not claim any virtue for
  21.     this code other than the virtue of working.  In fact there is a subtle
  22.     bug: if setof/bagof occurs as a data structure in the Generator it will
  23.     be mistaken for a call, and free variables treated wrongly.  Given the
  24.     current nature of Prolog, there is no way of telling a call from a data
  25.     structure, and since nested calls are FAR more likely than use as a
  26.     data structure, we just put up with the latter being wrong.  The same
  27.     applies to negation.
  28.  
  29.     Would anyone incorporating this in their Prolog system please credit
  30.     both me and David Warren;  he thought up the definitions, and my
  31.     implementation may owe more to subconscious memory of his than I like
  32.     to think.  At least this ought to put a stop to fraudulent claims to
  33.     having bagof, by replacing them with genuine claims.
  34.  
  35.     Thanks to Dave Bowen for pointing out an amazingly obscure bug: if
  36.     the Template was a variable and the Generator never bound it at all
  37.     you got a very strange answer!  Now fixed, at a price.
  38. */
  39.  
  40. /* **********************************************************************
  41.    SB-Prolog has the naming convention that library predicate names
  42.    begin with $.  I've taken the liberty of prepending $ to most of
  43.    O'Keefe's predicate names. -- SKDebray, Aug 1988.
  44. ********************************************************************** */
  45.  
  46. /* **********************************************************************
  47. :- public
  48.     findall/3,        %   Same effect as C&M p152
  49.     findall/4,        %   A variant I have found very useful
  50.     bag_of/3,        %   Like bagof (Dec-10 manual p52)
  51.     set_of/3.        %   Like setof (Dec-10 manual p51)
  52.  
  53. :- mode
  54.     bag_of(+,+,?),
  55.     $concordant_subset(+,+,-),
  56.     $concordant_subset(+,+,-,-),
  57.     $concordant_subset(+,+,+,+,-),
  58.     findall(+,+,?),
  59.     findall(+,+,+,?),
  60.     list_instances(+,-),
  61.     list_instances(+,+,-),
  62.     list_instances(+,+,+,-),
  63.     list_instances(+,+,+,+,-),
  64.     replace_key_variables(+,+,+),
  65.     save_instances(+,+),
  66.     set_of(+,+,?).
  67. ********************************************************************** */
  68.  
  69. $setof_export([$setof/3,$bagof/3,$findall/3,$sort/2,$keysort/2]).
  70.  
  71. /* $setof_use($meta,[$functor/3,$univ/2,$length/2]).
  72.    $setof_use($buff,[$alloc_perm/2,$alloc_heap/2,$trimbuff/3,$buff_code/4,
  73.         $symtype/2,
  74.         $substring/6,$subnumber/6,$subdelim/6,$conlength/2,
  75.         $pred_undefined/1, $hashval/3]).
  76.    $setof_use($bmeta,[$atom/1,$atomic/1,$integer/1,$number/1,$structure/1,
  77.     $functor0/2,$bldstr/3,$arg/3,$arity/2,$real/1,$float/1,_,_]).
  78. */
  79.  
  80. %   findall(Template, Generator, List)
  81. %   is a special case of bagof, where all free variables in the
  82. %   generator are taken to be existentially quantified.  It is
  83. %   described in Clocksin & Mellish on p152.  The code they give
  84. %   has a bug (which the Dec-10 bagof and setof predicates share)
  85. %   which this has not.
  86.  
  87. /* **********************************************************************
  88. % With SB-Prolog's current implementation of record/recorded, it's
  89. %  cheaper to use buff_code.  O'Keefe's original code was
  90.  
  91. findall(Template, Generator, List) :-
  92.     save_instances(-Template, Generator),
  93.     list_instances([], List).
  94.  
  95. %   findall(Template, Generator, SoFar, List) :-
  96. %    findall(Template, Generator, Solns),
  97. %    append(Solns, SoFar, List).
  98. %   But done more cheaply.
  99.  
  100. findall(Template, Generator, SoFar, List) :-
  101.     save_instances(-Template, Generator),
  102.     list_instances(SoFar, List).
  103. ********************************************************************** */
  104.  
  105. $findall(T,Call,Result) :-
  106.     $alloc_heap(5000,Buff),
  107.     $findall_1(T,Call,Result,Buff).
  108.  
  109. $findall_1(T,Call,Result,Buff) :-
  110.     $copyterm([],Buff,8,4,_), /* init result list to empty */
  111.     $buff_code(Buff,0,2 /*pn*/ ,8), /* init where to put next answer */
  112.     $buff_code(Buff,4,2 /*pn*/ ,12), /* init first free place */
  113.     call(Call),
  114.     $buff_code(Buff,0,5 /*gn*/ ,Place), /* get where to put answer */
  115.     $buff_code(Buff,4,5 /*gn*/ ,Start), /* get first free place */
  116.     $copyterm([T],Buff,Place,Start,End),
  117.     Tailloc is Start+4,    
  118.     $buff_code(Buff,0,2 /*pn*/ ,Tailloc), /* where to put next answer */
  119.     $buff_code(Buff,4,2 /*pn*/ ,End), /* next first free place */
  120.     fail.
  121.  
  122. $findall_1(_,_,Result,Buff) :-
  123.     $buff_code(Buff,4,5 /*gn*/ ,Length), /* Length =\= 12 fail if [] */
  124.     $trimbuff(Length,Buff,1),
  125.     $buff_code(Buff,8,18 /*vtb*/ ,Result).
  126.  
  127.  
  128. %   $setof(Template, Generator, Set)
  129. %   finds the Set of instances of the Template satisfying the Generator.
  130. %   The set is in ascending order (see compare/3 for a definition of
  131. %   this order) without duplicates, and is non-empty.  If there are
  132. %   no solutions, set_of fails.  set_of may succeed more than one way,
  133. %   binding free variables in the Generator to different values.  This
  134. %   predicate is defined on p51 of the Dec-10 Prolog manual.
  135.  
  136. $setof(Template, Filter, Set) :-
  137.     $bagof(Template, Filter, Bag),
  138.     $sort(Bag, Set).
  139.  
  140. %   $bagof(Template, Generator, Bag)
  141. %   finds all the instances of the Template produced by the Generator,
  142. %   and returns them in the Bag in they order in which they were found.
  143. %   If the Generator contains free variables which are not bound in the
  144. %   Template, it assumes that this is like any other Prolog question
  145. %   and that you want bindings for those variables.  (You can tell it
  146. %   not to bother by using existential quantifiers.)
  147. %   bag_of records three things under the key '.':
  148. %    the end-of-bag marker           -
  149. %    terms with no free variables   -Term
  150. %    terms with free variables   Key-Term
  151. %   The key '.' was chosen on the grounds that most people are unlikely
  152. %   to realise that you can use it at all, another good key might be ''.
  153. %   The original data base is restored after this call, so that set_of
  154. %   and bag_of can be nested.  If the Generator smashes the data base
  155. %   you are asking for trouble and will probably get it.
  156. %   The second clause is basically just findall, which of course works in
  157. %   the common case when there are no free variables.
  158.  
  159. $bagof(Template, Generator, Bag) :-
  160.     $free_variables(Generator, Template, [], Vars),
  161.     Vars \= [],
  162.     !,
  163.     Key =.. [.|Vars],
  164.     functor(Key, ., N),
  165. /* **********************************************************************
  166. % SB-Prolog version modified to use findall instead of record/recorded
  167. %    save_instances(Key-Template, Generator),
  168. %    list_instances(Key, N, [], OmniumGatherum),
  169. ********************************************************************** */
  170.         $findall(Key-Template,Generator,OmniumGatherum),
  171.     $keysort(OmniumGatherum, Gamut), !,
  172.     $concordant_subset(Gamut, Key, Answer),
  173.     Bag = Answer.
  174. $bagof(Template, Generator, Bag) :-
  175. /* **********************************************************************
  176. %    save_instances(-Template, Generator),
  177. %    list_instances([], Bag),
  178. ********************************************************************** */
  179.         $findall(Template,Generator,Bag).
  180.  
  181. /* **********************************************************************
  182. % In SB-Prolog, it's cheaper to use $buff_code than record/recorded, so
  183. % this code is never used and has been commented out.  O'Keefe's original
  184. % code is given below.  -- SKD, Aug 1988
  185.  
  186. %   save_instances(Template, Generator)
  187. %   enumerates all provable instances of the Generator and records the
  188. %   associated Template instances.  Neither argument ends up changed.
  189.  
  190. % save_instances(Template, Generator) :-
  191. %     recorda(., -, _),
  192. %     call(Generator),
  193. %     recorda(., Template, _),
  194. %     fail.
  195. % save_instances(_, _).
  196. %   list_instances(SoFar, Total)
  197. %   pulls all the -Template instances out of the data base until it
  198. %   hits the - marker, and puts them on the front of the accumulator
  199. %   SoFar.  This routine is used by findall/3-4 and by bag_of when
  200. %   the Generator has no free variables.
  201. % list_instances(SoFar, Total) :-
  202. %     recorded(., Term, Ref),
  203. %     erase(Ref), !,        %   must not backtrack
  204. %     list_instances(Term, SoFar, Total).
  205. % list_instances(-, SoFar, Total) :- !,
  206. %     Total = SoFar.        %   = delayed in case Total was bound
  207. % list_instances(-Template, SoFar, Total) :-
  208. %     list_instances([Template|SoFar], Total).
  209. %   list_instances(Key, NVars, BagIn, BagOut)
  210. %   pulls all the Key-Template instances out of the data base until
  211. %   it hits the - marker.  The Generator should not touch recordx(.,_,_).
  212. %   Note that asserting something into the data base and pulling it out
  213. %   again renames all the variables; to counteract this we use replace_
  214. %   key_variables to put the old variables back.  Fortunately if we
  215. %   bind X=Y, the newer variable will be bound to the older, and the
  216. %   original key variables are guaranteed to be older than the new ones.
  217. %   This replacement must be done @i<before> the keysort.
  218. % list_instances(Key, NVars, OldBag, NewBag) :-
  219. %     recorded(., Term, Ref),
  220. %     erase(Ref), !,        %  must not backtrack!
  221. %     list_instances(Term, Key, NVars, OldBag, NewBag).
  222. % list_instances(-, _, _, AnsBag, AnsBag) :- !.
  223. % list_instances(NewKey-Term, Key, NVars, OldBag, NewBag) :-
  224. %     replace_key_variables(NVars, Key, NewKey), !,
  225. %     list_instances(Key, NVars, [NewKey-Term|OldBag], NewBag).
  226. %   There is a bug in the compiled version of arg in Dec-10 Prolog,
  227. %   hence the rather strange code.  Only two calls on arg are needed
  228. %   in Dec-10 interpreted Prolog or C-Prolog.
  229. % replace_key_variables(0, _, _) :- !.
  230. % replace_key_variables(N, OldKey, NewKey) :-
  231. %     arg(N, NewKey, Arg),
  232. %     nonvar(Arg), !,
  233. %     M is N-1,
  234. %     replace_key_variables(M, OldKey, NewKey).
  235. % replace_key_variables(N, OldKey, NewKey) :-
  236. %     arg(N, OldKey, OldVar),
  237. %     arg(N, NewKey, OldVar),
  238. %     M is N-1,
  239. %     replace_key_variables(M, OldKey, NewKey).
  240. ********************************************************************** */
  241.  
  242. %   $concordant_subset([Key-Val list], Key, [Val list]).
  243. %   takes a list of Key-Val pairs which has been keysorted to bring
  244. %   all the identical keys together, and enumerates each different
  245. %   Key and the corresponding lists of values.
  246.  
  247. $concordant_subset([Key-Val|Rest], Clavis, Answer) :-
  248.     $concordant_subset(Rest, Key, List, More),
  249.     $concordant_subset(More, Key, [Val|List], Clavis, Answer).
  250.  
  251.  
  252. %   $concordant_subset(Rest, Key, List, More)
  253. %   strips off all the Key-Val pairs from the from of Rest,
  254. %   putting the Val elements into List, and returning the
  255. %   left-over pairs, if any, as More.
  256.  
  257. $concordant_subset([Key-Val|Rest], Clavis, [Val|List], More) :-
  258.     Key == Clavis,
  259.     !,
  260.     $concordant_subset(Rest, Clavis, List, More).
  261. $concordant_subset(More, _, [], More).
  262.  
  263.  
  264. %   $concordant_subset/5 tries the current subset, and if that
  265. %   doesn't work if backs up and tries the next subset.  The
  266. %   first clause is there to save a choice point when this is
  267. %   the last possible subset.
  268.  
  269. $concordant_subset([],   Key, Subset, Key, Subset) :- !.
  270. $concordant_subset(_,    Key, Subset, Key, Subset).
  271. $concordant_subset(More, _,   _,   Clavis, Answer) :-
  272.     $concordant_subset(More, Clavis, Answer).
  273.  
  274.  
  275. %   File   : NOT.PL
  276. %   Author : R.A.O'Keefe
  277. %   Updated: 17 November 1983
  278. %   Purpose: "suspicious" negation 
  279.  
  280. /*  This file defines a version of 'not' which checks that there are
  281.     no free variables in the goal it is given to "disprove".  Bound
  282.     variables introduced by the existential quantifier ^ or set/bag
  283.     dummy variables are accepted.  If any free variables are found, 
  284.     a message is printed on the terminal and a break level entered.
  285.  
  286.     It is intended purely as a debugging aid, though it shouldn't slow
  287.     interpreted code down much.  There are several other debugging
  288.     aids that you might want to use as well, particularly
  289.     unknown(_, trace)
  290.     which will detect calls to undefined predicates (as opposed to
  291.     predicates which have clauses that don't happen to match).
  292.  
  293.     The predicate $free_variables/4 defined in this files is also used
  294.     by the set_of/bag_of code.
  295.  
  296.     Note: in Dec-10 Prolog you should normally use "\+ Goal" instead
  297.     of "not(Goal)".  In C-Prolog you can use either, and would have to
  298.     do some surgery on pl/init to install this version of "not".  The
  299.     reason that I have called this predicate "not" is so that people
  300.     can choose whether to use the library predicate not/1 (in Invoca.Pl)
  301.     or this debugging one, not because I like the name.
  302. */
  303. /* **********************************************************************
  304. % :- public
  305. %     (not)/1.        %   new checking denial
  306. % :- mode
  307. %     $explicit_binding(+,+,-,-),
  308. %     $free_variables(+,+,+,-),
  309. %         $free_variables(+,+,+,+,-),
  310. %     $list_is_free_of(+,+),
  311. %     not(+),
  312. %     $term_is_free_of(+,+),
  313. %         $term_is_free_of(+,+,+).
  314. % :- op(900, fy, not).
  315. % not(Goal) :-
  316. %     $free_variables(Goal, [], [], Vars),
  317. %     Vars \== [], !,
  318. %     fwritef(user, '\n! free variables %t\n! in goal not(%t)\n',
  319. %         [Vars,Goal]),
  320. %     break,
  321. %     call(Goal),
  322. %     !, fail.
  323. % not(Goal) :-
  324. %     call(Goal),
  325. %     !, fail.
  326. % not(_).
  327. ********************************************************************** */
  328.  
  329. %   In order to handle variables properly, we have to find all the 
  330. %   universally quantified variables in the Generator.  All variables
  331. %   as yet unbound are universally quantified, unless
  332. %    a)  they occur in the template
  333. %    b)  they are bound by X^P, setof, or bagof
  334. %   $free_variables(Generator, Template, OldList, NewList)
  335. %   finds this set, using OldList as an accumulator.
  336.  
  337. $free_variables(Term, Bound, VarList, [Term|VarList]) :-
  338.     var(Term),
  339.     $term_is_free_of(Bound, Term),
  340.     $list_is_free_of(VarList, Term),
  341.     !.
  342. $free_variables(Term,_Bound, VarList, VarList) :-
  343.     var(Term),
  344.     !.
  345. $free_variables(Term, Bound, OldList, NewList) :-
  346.     $explicit_binding(Term, Bound, NewTerm, NewBound),
  347.     !,
  348.     $free_variables(NewTerm, NewBound, OldList, NewList).
  349. $free_variables(Term, Bound, OldList, NewList) :-
  350.     functor(Term, _, N),
  351.     $free_variables(N, Term, Bound, OldList, NewList).
  352.  
  353. $free_variables(0,_Term,_Bound, VarList, VarList) :- !.
  354. $free_variables(N, Term, Bound, OldList, NewList) :-
  355.     arg(N, Term, Argument),
  356.     $free_variables(Argument, Bound, OldList, MidList),
  357.     M is N-1, !,
  358.     $free_variables(M, Term, Bound, MidList, NewList).
  359.  
  360. %   $explicit_binding checks for goals known to existentially quantify
  361. %   one or more variables.  In particular \+ is quite common.
  362.  
  363. $explicit_binding(\+ _Goal,           Bound, fail,    Bound      ) :- !.
  364. $explicit_binding(not(_Goal),           Bound, fail,    Bound       ) :- !.
  365. $explicit_binding(Var^Goal,           Bound, Goal,    Bound+Var) :- !.
  366. $explicit_binding(setof(Var,Goal,Set),  Bound, Goal-Set, Bound+Var) :- !.
  367. $explicit_binding(bagof(Var,Goal,Bag),  Bound, Goal-Bag, Bound+Var) :- !.
  368. $explicit_binding(set_of(Var,Goal,Set), Bound, Goal-Set, Bound+Var) :- !.
  369. $explicit_binding(bag_of(Var,Goal,Bag), Bound, Goal-Bag, Bound+Var) :- !.
  370.  
  371.  
  372. /* **********************************************************************
  373.    Some recoding to make the code more efficient.  O'Keefe's original
  374.    code is:
  375.  
  376. % $term_is_free_of(Term, Var) :-
  377. %     var(Term), !,
  378. %     Term \== Var.
  379. % $term_is_free_of(Term, Var) :-
  380. %     functor(Term, _, N),
  381. %     $term_is_free_of(N, Term, Var).
  382. % $term_is_free_of(0,_Term,_Var) :- !.
  383. % $term_is_free_of(N, Term, Var) :-
  384. %     arg(N, Term, Argument),
  385. %     $term_is_free_of(Argument, Var),
  386. %     M is N-1, !,
  387. %     $term_is_free_of(M, Term, Var).
  388. ********************************************************************** */
  389.  
  390. $term_is_free_of(Term, Var) :-
  391.     var(Term) ->
  392.          Term \== Var ;
  393.          ($arity(Term, N),
  394.           $term_is_free_of(N, Term, Var)
  395.          ).
  396.  
  397. $term_is_free_of(N, Term, Var) :-
  398.     N =:= 0 ->
  399.          true ;
  400.          (arg(N, Term, Argument),
  401.           $term_is_free_of(Argument, Var),
  402.           M is N-1,
  403.           $term_is_free_of(M, Term, Var)
  404.          ).
  405.  
  406.  
  407. $list_is_free_of([Head|Tail], Var) :-
  408.     Head \== Var,
  409.     !,
  410.     $list_is_free_of(Tail, Var).
  411. $list_is_free_of([], _).
  412.  
  413. /*======================================================================*/
  414.  
  415. /* This routine copies a term into a buffer. It is passed:
  416.     Term: the term to copy,
  417.     Buffer: the buffer to copy it into,
  418.     Worddisp: the word of the buffer in which to put the copy (or
  419.         a pointer to the copy.)
  420.     Start: the disp of the next free location in the buffer, before the 
  421.         copy is done.
  422.     End: (returned) the location of the first free location after the
  423.         copying.
  424.  
  425.     Variables are copied into the buffer and the copied variables are
  426.     pointed into the buffer and trailed. Thus later binding of these 
  427.     `outside' variables will cause the copied variables to be changed,
  428.     too. If, however, the $copyterm call is failed over, the variables
  429.     in the buffer will be ``disconnected'' from the outer variables.
  430.  
  431.     Copyterm is a prime candidate for moving down into the simulator as
  432.     a builtin written in C.
  433. */
  434.  
  435.  
  436. $copyterm(Term,Buff,Worddisp,Start,Start) :-
  437.     var(Term),!,$buff_code(Buff,Worddisp,17 /*pvar*/ ,Term).
  438.  
  439. $copyterm(Term,Buff,Worddisp,Start,Start) :-
  440.     number(Term),!,$buff_code(Buff,Worddisp,14 /*ptv*/ ,Term).
  441.  
  442. $copyterm(Term,Buff,Worddisp,Start,Start) :-
  443.     $atom(Term),!,$buff_code(Buff,Worddisp,14 /*ptv*/ ,Term).
  444.  
  445. $copyterm(Term,Buff,Worddisp,Start,End) :-
  446.     Term=[_|_],!,
  447.     $buff_code(Buff,Worddisp,16 /*ptl*/ ,Start), /* ptr to list rec */
  448.     Newstart is Start+8, /* reserve rec space */
  449.     $copyargs(Term,1,2,Buff,Start,Newstart,End).
  450.     
  451. $copyterm(Term,Buff,Worddisp,Start,End) :-
  452.     $structure(Term),!,
  453.     $buff_code(Buff,Worddisp,15 /*ptp*/ ,Start), /* ptr to str rec */
  454.     $buff_code(Buff,Start,0 /*ppsc*/ ,Term), /* rec psc ptr */
  455.     Argsloc is Start+4,
  456.     $arity(Term,Arity),Newstart is Argsloc+4*Arity, /* reserve rec space*/
  457.     $copyargs(Term,1,Arity,Buff,Argsloc,Newstart,End).
  458.     
  459. $copyargs(Term,Argno,Maxargs,Buff,Argloc,Start,End) :- 
  460.     Argno > Maxargs,
  461.      Start=End;
  462.     Argno =< Maxargs,
  463.      arg(Argno,Term,Arg),$copyterm(Arg,Buff,Argloc,Start,Mid),
  464.      Nargno is Argno+1, Nargloc is Argloc+4,
  465.      $copyargs(Term,Nargno,Maxargs,Buff,Nargloc,Mid,End).
  466.  
  467.  
  468. /* Sorting by bisecting and merging. */
  469.  
  470. $sort(L,R) :- $length(L,N), $sort(N,L,_,R1), R=R1.
  471.  
  472. $sort(N,U,L,R) :-
  473.     N > 2 ->
  474.         (N1 is N >> 1, N2 is N-N1,
  475.          $sort(N1,U,L2,R1),
  476.          $sort(N2,L2,L,R2),
  477.          $merge(R1,R2,R)
  478.         ) ;
  479.         (N =:= 2 ->
  480.             (U = [X1|L1],
  481.              L1 = [X2|L],
  482.              $compare(Delta,X1,X2),
  483.              (Delta ?= (<) -> R = [X1,X2] ;
  484.               Delta ?= (>) -> R = [X2,X1] ;
  485.                         R = [X2]
  486.              )
  487.             ) ;
  488.             (N =:= 1 ->
  489.                 (U = [X|L], R = [X]) ;
  490.                 (U = L, R = [])        /* N == 0 */
  491.             )
  492.          ).
  493.  
  494. $merge([],R,R) :- !.
  495. $merge(R,[],R) :- !.
  496. $merge(R1,R2,[X|R]) :-
  497.    R1 = [X1|R1a], R2 = [X2|R2a],
  498.    $compare(Delta,X1,X2),
  499.    (Delta ?= (<) ->
  500.        (X = X1, $merge(R1a,R2,R)) ;
  501.        (Delta ?= (>) ->
  502.             (X = X2, $merge(R1,R2a,R)) ;
  503.         (X = X1, $merge(R1a,R2a,R))
  504.        )
  505.    ).
  506.  
  507. /* Sorting on keys by bisecting and merging. */
  508.  
  509. $keysort(L,R) :- $length(L,N), $keysort(N,L,_,R1), R=R1.
  510.  
  511. $keysort(N,U,L,R) :-
  512.     N > 2 ->
  513.          (N1 is N >> 1, N2 is N-N1,
  514.           $keysort(N1,U,L2,R1),
  515.              $keysort(N2,L2,L,R2),
  516.              $keymerge(R1,R2,R)
  517.          ) ;
  518.          (N =:= 2 ->
  519.               (U = [X1|L1],
  520.            L1 = [X2|L],
  521.            $compare_keys(Delta,X1,X2),
  522.            (Delta ?= (>) -> R = [X2,X1] ; R = [X1,X2])
  523.           ) ;
  524.           (N =:= 1 ->
  525.               (U = [X|L], R = [X]) ;
  526.             (U = L, R = [])        /* N == 0 */
  527.           )
  528.          ).
  529.  
  530. $keymerge([],R,R) :- !.
  531. $keymerge(R,[],R) :- !.
  532. $keymerge(R1,R2,[X|R]) :-
  533.    R1 = [X1|R1a], R2 = [X2|R2a],
  534.    $compare_keys(Delta,X1,X2),
  535.    (Delta ?= (>) ->
  536.         (X = X2, $keymerge(R1,R2a,R)) ;
  537.     (X = X1, $keymerge(R1a,R2,R))
  538.    ).
  539.  
  540. $compare_keys(Delta,K1-X1,K2-X2) :- $compare(Delta,K1,K2).
  541.  
  542. /*======================================================================*/
  543.  
  544. X^P :- call(P).
  545.  
  546. /*======================================================================*/
  547.  
  548. /* ------------------------------ $setof.P ------------------------------ */
  549.